import Schema from 'async-validator'
import { getObjectVal, isObject } from './util'
import { wxToast } from './wxUtil'

/**
 * 获取表单相关配置数据
 */
function getDataVal(source, self) {
  if (typeof source === 'function') {
    return source()
  } else if (typeof source === 'string') {
    return getObjectVal((self || this).data, source)
  }

  return source
}

/**
 * 获取错误提示
 * @param {Array} error 错误数组
 */
function getFormErrTips (error) {
  const tips = {}

  error.forEach(item => {
    const messages = item.message.split('-')
    tips[`${item.field}`] = messages.length === 1 ? messages[0] : {
      msg: messages[0],
      status: messages[1] || ''
    }
  })

  return tips
}

function getFormAttr (root, field) {
  return !root ? `${field}` : `${root}.${field}`
}

/**
 * 验证表单
 * @param {object} rule 验证规则
 * @param {object} form 验证内容
 * @returns {Promise}
 */
export function validator(rule = {}, form = {}) {
  return new Promise((resolve, reject) => {
    if (!isObject(rule) || !isObject(form)) reject(new Error('请传入参数'))
  
    const v = new Schema(rule)
    v.validate(form, (errors, fields) => {
      if (errors) {
        reject({
          errors,
          fields
        })
      } else {
        resolve()
      }
    })
  })
}

/**
 * 验证具体表单，
 * ruleSource（规则源）、formSource（需要验证的数据源）：格式：`a.b` -> this.data.a.b，或者getter函数
 * tipsKey：存储错误提示信息的key，在this.data下
 */
export async function verifyForm({ ruleSource, formSource, tipsKey = 'formTips', isErrToast = false } = {}, self) {
  const _self = self || this

  try {
    await validator(getDataVal.call(_self, ruleSource), getDataVal.call(_self, formSource))

    _self.setData({
      [`${tipsKey}`]: {}
    })
  } catch (error) {
    if (isObject(error) && Array.isArray(error.errors)) {
      if (isErrToast) {
        wx.showToast({
          title: error.errors[0].message.split('-')[0],
          icon: 'none'
        })
      } else {
        _self.setData({ [`${tipsKey}`]: getFormErrTips(error.errors) })
      }
    }

    throw error
  }
}

/**
 * 绑定文本框输入
 * @param {*} e 节点参数
 * @param {string} attr 数据来源
 */
export function formInputChange (e, root = 'formData') {
  const {
    field
  } = e.currentTarget.dataset

  const attr = getFormAttr(root, field)

  this.setData({
    [attr]: typeof e.detail === 'string' ? e.detail : e.detail.value
  })
}

/**
 * 创建提交函数
 */
export function createSubmit(
  api,
  {
    loadKey = 'submitting',
    load,
    msg = '提交成功',
    ruleSource,
    formSource,
    tipsKey,
    isErrToast
  } = {},
  self
) {
  return async function () {
    const _self = self || this

    if (getDataVal.call(_self, loadKey)) return

    load && wx.showLoading({ mask: true, title: load })
    _self.setData({ [`${loadKey}`]: true })

    try {
      await verifyForm({ ruleSource, formSource, tipsKey, isErrToast }, _self)
      const callback = await api.call(_self)

      if (msg) {
        wxToast({
          title: msg,
          icon: 'success',
          onClose: callback
        })
      } else {
        callback && typeof callback === 'function' && callback()
      }
    } catch (error) {
      console.error(error)
    } finally {
      load && wx.hideLoading()
      _self.setData({ [`${loadKey}`]: false })
    }
  }
}
